package com.moyun.controller.system;


import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.moyun.common.annotation.OperLog;
import com.moyun.common.aspect.BusinessType;
import com.moyun.common.mapstruct.SysUserConvertMapper;
import com.moyun.common.validation.SysUserModifyGroup;
import com.moyun.common.enums.CodeEnum;
import com.moyun.common.excel.listener.SysUserEntityExcelListener;
import com.moyun.common.utils.MemorySessionUtil;
import com.moyun.common.utils.ResultUtil;
import com.moyun.common.utils.SystemUtil;
import com.moyun.model.common.R;
import com.moyun.model.param.system.ImportUserParam;
import com.moyun.model.param.system.SysUserEntityParam;
import com.moyun.model.po.system.SysUserEntity;
import com.moyun.service.system.SysUserService;
import com.moyun.syssecurity.config.MyPasswordEncoder;
import com.moyun.syssecurity.util.SecurityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;


/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author yangboxuan
 * @since 2021-07-01
 */
@Api(tags = "系统用户")
@RestController
@RequestMapping("/security/sys-user")
public class SysUserController {
    @Autowired
    private SysUserService sysUserEntityService;
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private SessionRegistry sessionRegistry;
    @Autowired
    private Environment env;
    @Autowired
    private MyPasswordEncoder myPasswordEncoder;
    @Autowired
    private MemorySessionUtil memorySessionUtil;
    //    @Autowired
//    private RedisSessionUtil redisSessionUtil;
    @Autowired
    private SysUserConvertMapper sysUserConvertMapper;


    private static final String FILE_ZIP = "zip";
    private static final String FILE_XLS = ".xls";
    private static final String FILE_XLSX = ".xlsx";

    /**
     * @return com.moyun.common.web.JsonResult
     * @Author yangboxuan
     * @Description 添加数据
     * @Date 2021-07-01
     * @Param [sysUserEntity]
     **/
    @ApiOperation("添加数据")
    @PostMapping(value = "/save")
    @OperLog(operModul = "系统用户模块", operType = BusinessType.INSERT, operDesc = "添加数据")
    public R save(@RequestBody @Validated SysUserEntityParam sysUserEntityParam) {
        // 1. 判断用户密码是否为空
        if (StringUtils.isEmpty(sysUserEntityParam.getUserPassword())) {
            // 1.1获取系统默认的用户初始密码并加密
            sysUserEntityParam.setUserPassword(this.myPasswordEncoder.encode(this.env.getProperty("moyun-base.password.user-default")));
        } else {
            // 1.2获取用户输入的密码并加密
            sysUserEntityParam.setUserPassword(this.myPasswordEncoder.encode(sysUserEntityParam.getUserPassword()));
        }
        QueryWrapper<SysUserEntity> sysUserEntityQueryWrapper = new QueryWrapper<>();
        sysUserEntityQueryWrapper.eq("user_name", sysUserEntityParam.getUserName());
        SysUserEntity one = this.sysUserEntityService.getOne(sysUserEntityQueryWrapper);
        if (!Objects.isNull(one)) {
            return R.error(CodeEnum.FAIL.getCode(),"用户id重复");
        }
        SysUserEntity sysUserEntity = this.sysUserConvertMapper.sysUserEntityParamtoSysUserEntity(sysUserEntityParam);
        boolean flag = this.sysUserEntityService.save(sysUserEntity);
        if (flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }

    @ApiOperation("更新数据(改)")
    @ApiOperationSupport(order = 3)
    @OperLog(operModul = "", operType = BusinessType.UPDATE, operDesc = "")
    @PutMapping("/update")
    public R update(@RequestBody @Validated({SysUserModifyGroup.class}) SysUserEntity entity) {
        boolean isUpdate = this.sysUserEntityService.updateById(entity);
        return isUpdate ? R.ok(0, "操作成功") : R.error(1, "操作失败");
    }

    @ApiOperation("剔除用户(使用户下线)")
    @PostMapping("take-the-user-offline")
    @OperLog(operModul = "系统用户模块", operType = BusinessType.OTHER, operDesc = "剔除用户(使用户下线)")
    public R takeTheUserOffline(@RequestParam("username") String username) {
        boolean flag = memorySessionUtil.sessionRegistryRemoveUserByLoginName(username);
//        boolean flag = redisSessionUtil.sessionRegistryRemoveUserByLoginName(username);
        if (flag) {
            return R.ok("剔除成功");
        } else {
            return R.error("剔除失败");
        }

    }

    @ApiOperation("获取用户在线人数")
    @GetMapping("get-online-count")
    @OperLog(operModul = "系统用户模块", operType = BusinessType.OTHER, operDesc = "获取用户在线人数")
    public R getOnlineCount() {
        List<Object> allPrincipalsFromSessionRegistry = memorySessionUtil.getAllPrincipalsFromSessionRegistry();
        int count = allPrincipalsFromSessionRegistry.size();
        return R.ok(count);

    }


    @GetMapping("/test01")
//    @PreAuthorize("hasRole('xxxxxxxxxx')")
    public R test01(Authentication authentication) {
        SysUserEntity loginUser = SecurityUtil.getLoginUser();
        List<Object> allPrincipalsFromSessionRegistry1 = memorySessionUtil.getAllPrincipalsFromSessionRegistry();
        List<Object> allPrincipals1 = sessionRegistry.getAllPrincipals();
//        List allPrincipals = sessionBackedSessionRegistry.getAllPrincipals();
        System.out.println("hahahahahaha");
        return R.ok(allPrincipals1.size());

    }

    @ApiOperation("导入")
    @PostMapping("import-user")
    public R<?> importUser(@RequestParam("file") MultipartFile multipartFile, HttpServletResponse response) throws IOException {
        /**
         * 判断文件类型是否正确
         */
        if (multipartFile == null) {
//            HttpServletResponseUtil.printJson(JSON.toJSONString(ResultUtil.fail(CodeEnum.ERROR_EXCEL_TYPE)));
            return ResultUtil.fail(CodeEnum.ERROR_EXCEL_TYPE);
        }
        String originalFilename = multipartFile.getOriginalFilename();
        String fileType = null;
        if (originalFilename != null) {
            fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        /**
         * 先判断后缀名
         */
        if (!(FILE_XLS.equalsIgnoreCase(fileType) || FILE_XLSX.equalsIgnoreCase(fileType))) {
            return ResultUtil.fail(CodeEnum.ERROR_EXCEL_TYPE);
        }
        // 这里有一个bug,第二个参数 Class head,如果设置了,那么第三个参数 ReadListener readListener 指定的泛型不起作用。有参构造,指定的参数也不起作用
        // 具体请查看官网的 issues https://github.com/alibaba/easyexcel/issues/93 AnalysisEventListener 不支持泛型吗，我一个子类继承AnalysisEventListener
//        EasyExcel.read(multipartFile.getInputStream(), Person.class, new MyExcelImportAnalysisEventListener(new SysSettingVo()))
//                .sheet().doRead();

        SysUserEntityExcelListener<ImportUserParam> listener = new SysUserEntityExcelListener<>();

        /*EasyExcel.read(multipartFile.getInputStream(), listener)
                .sheet().doRead();*/

        /**
         * 进行数据读取入库操作
         */
        EasyExcel.read(multipartFile.getInputStream(), ImportUserParam.class, listener)
                .sheet().doRead();


        List<List<Object>> errorData = listener.getErrorData();
        if (!CollectionUtils.isEmpty(errorData)) {
            /**
             * 错误数据下载
             * 目前: 直接下载到桌面
             * 方式一: 将excel先下载到本地,之后再发起请求,重新下载. 定期删除
             * 方式二: 将数据放到中间件上,之后再发起请求,读取数据，重新下载. 定期删除
             */
            EasyExcel.write(new File(SystemUtil.getUserHome() + "\\Desktop\\error.xlsx")).head(listener.getHead()).sheet("系统用户").doWrite(errorData);
            return R.error(CodeEnum.FAIL.getCode(), "成功" + listener.getSuccessCount() + "条,失败" + listener.getErrorCount() + "条");
        } else {
            return R.ok(CodeEnum.SUCCESS.getCode(), "共导入" + listener.getSuccessCount() + "条数据");
        }
    }


}

